package org.essilab.analyzer.analyzer;

import java.io.*;
import java.util.zip.GZIPInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

/**
 *
 * @author Mohamed-Amine Chouchene, Ahcène Idinarere, Vincent Nock, Alain
 * Janin-Manificat
 */
public class XmlParser extends DefaultHandler {

    private static final String FILE_TITLE = "title";
    private static final String FILE_TEXT = "text";
    private static final String FILE_PAGE = "page";
    private static final String FILE_TIMESTAMP = "timestamp";
    private Page fPage;
    private StringBuilder fText;
    private XMLReader fXMLReader;
    private Reader fReader;
    private IArticle fArticle;

    /**
     * XMLParser constructor that take a Strign as parameter.
     *
     * @param filename String
     * @param article IArticle
     * @see XmlParser#XmlParser(java.io.Reader,
     * org.essilab.analyzer.analyzer.IArticle)
     * @throws UnsupportedEncodingException
     * @throws IOException
     * @throws SAXException
     * @throws FileNotFoundException
     */
    public XmlParser(String filename, IArticle article) throws UnsupportedEncodingException, IOException, SAXException, FileNotFoundException {
        this(getBufferedReader(filename), article);
    }

    /**
     * XMLParser constructor that take an InputStream as parameter. Init an
     * XMLReader and a Reader from given InputStream.
     *
     * @param inputStream InputStream
     * @param article IArticle
     * @throws SAXException
     */
    public XmlParser(InputStream inputStream, IArticle article) throws SAXException {
        super();
        try {
            fArticle = article;
            fXMLReader = XMLReaderFactory.createXMLReader();
            fXMLReader.setContentHandler(this);
            fXMLReader.setErrorHandler(this);
            fReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    /**
     * XMLParser constructor that take a Reader as parameter. Init an
     * XMLReader and a Reader from given FileReader.
     *
     * @param reader Reader
     * @param article IArticle
     * @throws SAXException
     */
    public XmlParser(Reader reader, IArticle article) throws SAXException {
        super();
        fArticle = article;
        fXMLReader = XMLReaderFactory.createXMLReader();
        fXMLReader.setContentHandler(this);
        fXMLReader.setErrorHandler(this);
        fReader = reader;
    }

    /**
     * Obtain a BufferedReader from given dump file.
     *
     * @param dumpFilename String - path of the dump file of words.
     * @return BufferedReader - a BufferedReader to read the target dump file.
     * @throws UnsupportedEncodingException
     * @throws FileNotFoundException
     * @throws IOException
     */
    public static BufferedReader getBufferedReader(String dumpFilename) throws UnsupportedEncodingException, FileNotFoundException, IOException {
        BufferedReader br = null;
        if (dumpFilename.endsWith(".gz")) {
            br = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(dumpFilename)), "UTF-8"));
        } else if (dumpFilename.endsWith(".bz2")) {
            FileInputStream fis = new FileInputStream(dumpFilename);
            br = new BufferedReader(new InputStreamReader(new BZip2CompressorInputStream(fis), "UTF-8"));
        } else {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(dumpFilename), "UTF-8"));
        }
        return br;
    }

    /**
     * Return the current XMLParser#ftext and set it to null.
     *
     * @return String - XMLParser#ftext String value.
     */
    private String getString() {
        if (fText == null) {
            return null;
        } else {
            String s = fText.toString();
            fText = null;
            return s;
        }
    }

    @Override
    public void startDocument() {
    }

    @Override
    public void endDocument() {
    }

    @Override
    /**
     * Init a new Page.
     */
    public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {
        fText = null;
        if (FILE_PAGE.equals(qName)) {
            fPage = new Page();
        }
    }

    @Override
    /**
     * Set Page properties.
     * Process the article and create the terms.
     */
    public void endElement(String uri, String name, String qName) throws SAXException {
        try {
            if (null != fPage) {
                if (FILE_PAGE.equals(qName)) {
                } else if (FILE_TEXT.equals(qName)) {
                    fPage.setText(getString());
                    fArticle.process(fPage);
                } else if (FILE_TITLE.equals(qName)) {
                    fPage.setTitle(getString());
                } else if (FILE_TIMESTAMP.equals(qName)) {
                    fPage.setTimeStamp(getString());
                }
            }
            fText = null;
        } catch (RuntimeException re) {
            re.printStackTrace();
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if (fText == null) {
            fText = new StringBuilder(length);
        }
        fText.append(ch, start, length);
    }

    /**
     * Parse the XML file using this class XMLReader.
     * @throws IOException
     * @throws SAXException
     */
    public void parse() throws IOException, SAXException {
        fXMLReader.parse(new InputSource(fReader));
    }
}
